﻿using System;
using System.IO;
using ExFlash.Tags;
using System.Collections.Generic;
using Be.Windows.Forms;
using ICSharpCode.SharpZipLib.Zip.Compression;

namespace ExFlash
{
    public class FlashFile : IDisposable, IDictionaryIdQueryable
    {
        private Boolean _isDisposed;
        private readonly Dictionary<ushort, Tag> _idDictionary;
        private readonly List<Tag> _tags;

        public SwfHeader Header
        {
            get;
            private set;
        }

        public int UncompressedLength
        {
            get;
            private set;
        }

        public IByteProvider ByteProvider
        {
            get;
            private set;
        }

        public IEnumerable<Tag> Tags
        {
            get
            {
                foreach (Tag tag in _tags)
                {
                    yield return tag;
                }
            }
        }

        public FlashFile()
        {
            _idDictionary = new Dictionary<ushort, Tag>();
            _tags = new List<Tag>();
        }

        public void Load(Stream st)
        {
            Byte[] headerBuffer = new byte[SwfHeader.HeaderSize];
            st.Read(headerBuffer, 0, SwfHeader.HeaderSize);
            UncompressedLength = (int)SwfHeader.GetFileLength(headerBuffer,4);
            MemoryStream memst = new MemoryStream(UncompressedLength);

            if (SwfHeader.CheckCompression(headerBuffer,0))
            {
                byte[] compressed = new byte[UncompressedLength];

                byte[] uncompressed = new byte[UncompressedLength];
                st.Read(compressed,0,UncompressedLength);

                Inflater zipInflator = new Inflater();
                zipInflator.SetInput(compressed);

                memst.Write(headerBuffer, 0, 8);

                zipInflator.Inflate(uncompressed, 0, UncompressedLength - 8);

                memst.Write(uncompressed, 0, UncompressedLength - 8);
            }

            memst.Seek(0, SeekOrigin.Begin);
            BinaryBitReader reader = new BinaryBitReader(memst);

            Header = new SwfHeader();
            Header.SwfDeserialize(reader);

            TagAssistant tagCreator = new TagAssistant(reader, Header.Version, _idDictionary);

            try
            {
                tagCreator.PopulateTags(_tags);
            }
            catch(Exception)
            {

            }

            ByteProvider = new DynamicFileByteProvider(memst);
        }

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(Boolean disposing)
        {
            // Check to see if Dispose has already been called.
            if (_isDisposed == false)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    
                    IDisposable disposableByteProvider = ByteProvider as IDisposable;

                    if (disposableByteProvider != null)
                    {
                        disposableByteProvider.Dispose();
                    }
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here.
                // If disposing is false, 
                // only the following code is executed.
                
                _isDisposed = true;
            }
        }

        ~FlashFile()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }

        public bool TryGetValue(ushort id, out Tag tag)
        {
            return _idDictionary.TryGetValue(id, out tag);
        }

        #endregion
    }
}
